﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  CompositeMessage.cs
//    
// Abstract:
//
//  This module is an implementation of IMessageSender for delivering NotificationItems
//  via multiple channels in series until one succeeds.
//  
//--

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Microsoft.EnhancedReminders.Dispatcher
{
    /// <summary>
    /// This module is an implementation of IMessageSender for delivering NotificationItems
    /// via multiple channels in series until one succeeds.
    /// </summary>
    public sealed class CompositeMessageSender : IMessageSender
    {
        private IList<IMessageSender> _channels;
        private int _currentChannel;

        #region IMessageSender Members

        /// <summary>
        /// Event fired when the attempt to deliver the message has been completed.
        /// </summary>
        public event EventHandler<DeliveryCompletedEventArgs> DeliverMessageCompleted;

        /// <summary>
        /// ctor.
        /// </summary>
        public CompositeMessageSender(IList<IMessageSender> channels)
        {
            _channels = channels;
        }

        /// <summary>
        /// Attempt to deliver a message across multiple channels in series until either
        /// one is successful or all have failed.
        /// </summary>
        public void DeliverMessageAsync()
        {
            Debug.Assert(_channels.Count > 0, "channels.Count > 0");

            _channels[_currentChannel].DeliverMessageCompleted += SenderDeliverMessageCompleted;
            _channels[_currentChannel].DeliverMessageAsync();
        }

        /// <summary>
        /// Event handler for when message delivery has completed.
        /// </summary>
        private void SenderDeliverMessageCompleted(object sender, DeliveryCompletedEventArgs e)
        {
            Debug.Assert(e != null, "e != null");
            Debug.Assert(e.Result != null, "e.Result != null");
            Debug.Assert(_currentChannel < _channels.Count, "_currentChannel < _channels.Count");

            _channels[_currentChannel].DeliverMessageCompleted -= SenderDeliverMessageCompleted;

            StopPointAttribute stopPoint = Attribute.GetCustomAttribute(_channels[_currentChannel].GetType(), 
                        typeof(StopPointAttribute)) as StopPointAttribute;
            Debug.Assert(stopPoint != null, "Channel does not define StopPointAttribute");

            if ((e.Result.Status == NotificationResultStatus.Success && stopPoint.IsStopPoint)
                || _channels.Count - 1 <= _currentChannel)
            {
                EventHandler<DeliveryCompletedEventArgs> callback = DeliverMessageCompleted;

                if (callback != null)
                {
                    callback(this, e);
                }
            }
            else if (_channels.Count - 1 > _currentChannel)
            {
                _currentChannel++;
                _channels[_currentChannel].DeliverMessageCompleted += SenderDeliverMessageCompleted;
                _channels[_currentChannel].DeliverMessageAsync();
            }
        }

        #endregion
    }
}
